package com.shm.leetcode;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
/**
 * @author: shm
 * @dateTime: 2020/10/29 9:59
 * @description: 129. 求根到叶子节点数字之和
 * 给定一个二叉树，它的每个结点都存放一个 0-9 的数字，每条从根到叶子节点的路径都代表一个数字。
 *
 * 例如，从根到叶子节点路径 1->2->3 代表数字 123。
 *
 * 计算从根到叶子节点生成的所有数字之和。
 *
 * 说明: 叶子节点是指没有子节点的节点。
 *
 * 示例 1:
 *
 * 输入: [1,2,3]
 *     1
 *    / \
 *   2   3
 * 输出: 25
 * 解释:
 * 从根到叶子节点路径 1->2 代表数字 12.
 * 从根到叶子节点路径 1->3 代表数字 13.
 * 因此，数字总和 = 12 + 13 = 25.
 * 示例 2:
 *
 * 输入: [4,9,0,5,1]
 *     4
 *    / \
 *   9   0
 *  / \
 * 5   1
 * 输出: 1026
 * 解释:
 * 从根到叶子节点路径 4->9->5 代表数字 495.
 * 从根到叶子节点路径 4->9->1 代表数字 491.
 * 从根到叶子节点路径 4->0 代表数字 40.
 * 因此，数字总和 = 495 + 491 + 40 = 1026.
 */
public class SumNumbers {
    public int sumNumbers(TreeNode root) {
        List<String> list = new ArrayList<>();
        int sum = 0;
        dfs(root,list,new StringBuffer());
        for(String s:list){
            sum+=Integer.parseInt(s);
        }
        return sum;
    }

    public void dfs(TreeNode node,List<String> list,StringBuffer ss){
        if(node==null){
            return;
        }
        ss.append(node.val);
        if(node.left==null&&node.right==null){
            list.add(new String(ss));
            return;
        }
        dfs(node.left,list,ss);
        if(node.left!=null){
            ss.deleteCharAt(ss.length()-1);
        }

        dfs(node.right,list,ss);
        if(node.right!=null){
            ss.deleteCharAt(ss.length()-1);
        }
    }

    /**
     * @author: shm
     * @dateTime: 2020/10/29 9:43
     * @description: 前言
     * 这道题中，二叉树的每条从根节点到叶子节点的路径都代表一个数字。其实，每个节点都对应一个数字，等于其父节点对应的数字乘以 1010 再加上该节点的值（这里假设根节点的父节点对应的数字是 00）。只要计算出每个叶子节点对应的数字，然后计算所有叶子节点对应的数字之和，即可得到结果。可以通过深度优先搜索和广度优先搜索实现。
     *
     * 方法一：深度优先搜索
     * 思路与算法
     *
     * 深度优先搜索是很直观的做法。从根节点开始，遍历每个节点，如果遇到叶子节点，则将叶子节点对应的数字加到数字之和。如果当前节点不是叶子节点，则计算其子节点对应的数字，然后对子节点递归遍历。
     *
     * 复杂度分析
     *
     * 时间复杂度：O(n)O(n)，其中 nn 是二叉树的节点个数。对每个节点访问一次。
     *
     * 空间复杂度：O(n)O(n)，其中 nn 是二叉树的节点个数。空间复杂度主要取决于递归调用的栈空间，递归栈的深度等于二叉树的高度，最坏情况下，二叉树的高度等于节点个数，空间复杂度为 O(n)O(n)。
     * 作者：LeetCode-Solution
     * 链接：https://leetcode-cn.com/problems/sum-root-to-leaf-numbers/solution/qiu-gen-dao-xie-zi-jie-dian-shu-zi-zhi-he-by-leetc/
     */
    public int sumNumbers_2(TreeNode root) {
        return dfs(root,0);
    }

    public int dfs(TreeNode node,int pre){
        if (node==null){
            return 0;
        }
        int sum = pre*10+node.val;
        if (node.right==null&&node.left==null){
            return sum;
        }else {
            return dfs(node.left,sum)+dfs(node.right,sum);
        }
    }

    /**
     * @author: shm
     * @dateTime: 2020/10/29 9:58
     * @description: 方法二：广度优先搜索
     * 思路与算法
     *
     * 使用广度优先搜索，需要维护两个队列，分别存储节点和节点对应的数字。
     *
     * 初始时，将根节点和根节点的值分别加入两个队列。每次从两个队列分别取出一个节点和一个数字，进行如下操作：
     *
     * 如果当前节点是叶子节点，则将该节点对应的数字加到数字之和；
     *
     * 如果当前节点不是叶子节点，则获得当前节点的非空子节点，并根据当前节点对应的数字和子节点的值计算子节点对应的数字，然后将子节点和子节点对应的数字分别加入两个队列。
     *
     * 搜索结束后，即可得到所有叶子节点对应的数字之和。
     * 复杂度分析
     *
     * 时间复杂度：O(n)O(n)，其中 nn 是二叉树的节点个数。对每个节点访问一次。
     *
     * 空间复杂度：O(n)O(n)，其中 nn 是二叉树的节点个数。空间复杂度主要取决于队列，每个队列中的元素个数不会超过 nn。
     *
     * 作者：LeetCode-Solution
     * 链接：https://leetcode-cn.com/problems/sum-root-to-leaf-numbers/solution/qiu-gen-dao-xie-zi-jie-dian-shu-zi-zhi-he-by-leetc/
     */
    public int sumNumbers_3(TreeNode root) {
        if (root==null){
            return 0;
        }
        int sum = 0;
        Queue<TreeNode> nodeQueue = new LinkedList<>();
        Queue<Integer> numQueue = new LinkedList<>();
        nodeQueue.offer(root);
        numQueue.offer(root.val);
        while (!nodeQueue.isEmpty()){
            TreeNode poll = nodeQueue.poll();
            Integer num = numQueue.poll();
            TreeNode left = poll.left,right=poll.right;
            if (left==null&&right==null){
                sum+=num;
            }else {
                if (left!=null){
                    nodeQueue.offer(left);
                    numQueue.offer(num*10+left.val);
                }
                if (right!=null){
                    nodeQueue.offer(right);
                    numQueue.offer(num*10+right.val);
                }
            }
        }
        return sum;
    }
}
